/**
 * 通用验证工具：一般验证+表单验证
 * 引入：import validate  from  ./validate.js
 * 一、表单验证
 *（一）、使用方法
 *  1、组织待提交的表单数据
	var postForm={//提交到服务器的的表单数据
		name: '',
		sn:"",
		pswd:"",
		email:"",
		tel:""
		content: '', 
		categoryId: null
	}
    2、定义验证规则
	let validRules = [
		{
			name: 'name',
			title: '名称',
			required: true,
			minLength: 4
		},
		{
			name: 'sn',
			title: 'sn编码',
			required: true,
			minLength: 4
		} 
	];
	3、调用valid方法验证
	var r=validate.valid(postForm, validRules);
	if(!r.isOk){
		alert(r.msg)
	}
  （二）、表单验证规则
	let validRules = [
		{
			name: 'name',//验证的表单字段英文名
			title: '名称',//验证的表单字段中文名
			type:'url|email|number|int|tel|password|NumberLetter|regex',//验证类型：网址|邮件|数字|整数|电话|密码|数字字符|正则表达式
			required: true,//是否必填不能为空
			minLength: 4,//字符串最小长度
			maxLength:12,//字符串最大长度
			min:10,//数字最小值
			max:10000,//数字最大值
			eq:"name2",//验证两个字段的值是否相等，name2为要比较的字段名
            eqTitle:'',//验证两个字段的值是否相等，不相等时的错误提示消息
			regex:'',//当type值为regex时的正则表达式，如： {name: 'xxx', type: 'regex', regex: /^1[0-9]{10,10}$/, msg: 'xxx'}
			msg:''//当验证不通过时候的自定义错误提示消息
		}
	];
	
	二、一般验证
	validate.isBoolean(obj)：判定obj是否是布尔类型对象
	validate.isNumber(obj)：判定obj是否是数字类型对象
	validate.isString(obj)：判定obj是否是字符串类型对象
	validate.isFunction(obj)：判定obj是否是函数类型对象
	validate.isArray(obj)：判定obj是否是数组类型对象
	validate.isDate(obj)：判定obj是否是日期类型对象
	validate.isRegExp(obj)：判定obj是否是正则表达式类型对象
	validate.isObject(obj)：判定obj是否是对象类型
	validate.isError(obj)：判定obj是否是错误类型对象
	validate.isLikeArray(obj)：判定obj是否是类数组类型，通过判断对象 是否具有length属性
	validate.isNull(obj)：判定obj对象是否为null或者undefined
	validate.isBlank(obj)：判定obj字符串是否为空
	validate.isEmpty(obj)：判定obj检查对象是否为空对象,即对象没有任何属性.判断对象是否为空即没有属性，通常用于判断{}
	validate.isNumber(obj)：判断值是否为数字
	validate.isEmail(obj)：判定obj是否是邮件字符串
	validate.isHtml(obj)：判定obj是否是HTML标签
	validate.containHtml(obj)：判定obj是否包含HTML标签
	validate.isUrl(obj)：判定obj是否是网址字符串
	validate.isInt(obj)：判定obj是否是整数类型
	validate.isPhone(obj)：判定obj是否是手机字符串
	validate.isPswd(obj)：判定obj是否是满足条件的密码，可以根据需要自定义规则
	validate.isNumberLetter(obj)：判定obj是否是数字字母字符串
	
 */
export default (function() {
	var $ = {};
	//判断是否是布尔/数字/字符串/函数/数字/日期/正则表达式类型
	var class2type = {};
	["Boolean", "Number", "String", "Function", "Array", "Date", "RegExp", "Object", "Error"].forEach(function(name, i) {
		class2type["[object " + name + "]"] = name.toLowerCase();
	});

	function type(obj) {
		if (obj == null) return obj + "";
		return typeof obj === "object" || typeof obj === "function" ?
			class2type[toString.call(obj)] || "object" :
			typeof obj;
	}
	["Boolean", "String", "Function", "Array", "Date", "RegExp", "Object", "Error"].forEach(function(name, i) {
		$["is" + name] = function(obj) {
			return type(obj) == name.toLowerCase();
		}
	});
	//rules格式{all:[{fn:fn,msg:"",name:"规则名称"}]}
	var _rules = { //验证规则
		common: [], //通用验证规则
		password: [], //密码验证规则
		email: [], //邮箱验证规则
		number: [], //数字验证规则
		url: [],
		number: []
	};
	Object.assign($, {
		isLikeArray: function(obj) {
			return obj ? typeof obj.length == 'number' : null;
		},
		/**
		 * 对象是否为null或者undefined
		 */
		isNull: function(obj) {
			return obj === null || obj === undefined
		},
		/**
		 * 字符串是否为空
		 */
		isBlank: function(str) {
			return $.isNull(str) || str.trim() == "";
		},
		/**
		 *  检查对象是否为空对象,即对象没有任何属性.判断对象是否为空即没有属性，通常用于判断{}
		 */
		isEmpty: function(obj) {
			if (!$.isObject(obj))
				return true;
			for (var attr in obj) {
				return false;
			}
			return true;
		},
		/**
		 * 判断值是否为数字
		 */
		isNumber: function(val) {
			return !$.isBlank(val) && (!isNaN(val) || typeof val == "number");
		},
		/**
		 * 
		 * @param {Object} value
		 */
		isEmail: function(value) {
			return /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
				.test(value);
		},
		isHtml: function(val) {
			return /^<([^>\s]+)[^>]*>(.*?<\/\\1>)?$/.test(val);
		},
		containHtml: function(val) {
			return /<[^>]+>/g.test(val);
		},
		isUrl: function(value) {
			return /^((http|https):\/\/(\w+:{0,1}\w*@)?(\S+)|)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/.test(value);
		},
		isInt: function(val) {
			return /^-?[1-9][0-9]*$/.test(val)
		},
		isPhone: function(val) {
			return /^1[0-9]{10,10}$/.test(val)
		},
		isPswd: function(val) {
			return /^.{6,16}$/.test(val)
		},
		isNumberLetter: function(val) { //是否是数字字母字符串
			return /^[a-zA-Z0-9]{1,}$/.test(val)
		},
		/**
		 * 如果一个参数,表示添加一个通用验证规则,如果两个参数,表示添加对应类型的验证规则
		 * @param {Object} type 一个参数时表示通用验证规则,两个参数时表示验证类型
		 * @param {Object} rule 此参数存在时,表示对应验证类型type的验证规则
		 */
		addRule: function(type, rule) {
			if (arguments.length == 2) {
				if (!_rules[type]) _rules[type] = [];
				_rules[type].push(rule);
			} else {
				_rules.common.push(type);
			}
			return $;
		},
		//验证数据data={username:"",pswd:"",email:"",tel:""} 
		//rules=[{name:'',title:"", type:'', msg:'', min:1, max:2,minLength:"",maxLength:"" eq:'',eqTitle:'', required:Boolean, regex:''}	]
		
		valid: function(data, rules) {
			let ret = {
				isOk: true,
				msg: '验证成功'
			}
			if (!rules || !rules.length) {
				return ret;
			}

			for (let rule of rules) {
				// rule: {name:'',title:"", type:'', msg:'', min:1, max:2,minLength:"",maxLength:"" eq:'', required:Boolean, regex:''}					
				if (!rule || !rule.name) {
					continue
				}
				var val = data[rule.name]; //验证的值
				var type = rule.type,
					title = rule.title || rule.name,
					__rules = [];
				//验证规则
				if (_rules[type]) {
					__rules = __rules.concat(_rules[type]);
				};
				__rules = __rules.concat(_rules.common)
				//循环
				for (let _rule of __rules) {
					_rule.title = title;
					var r = _rule.fn.call(_rule, val, rule, data);
					// 发现任何一个错误就立即返回，后面的不再判断
					if (!r) {
						ret = {
							isOk: false,
							msg: rule.msg||_rule.error || _rule.msg
						}
						return ret;
					}
				}
			}
			return ret;
		}
	});
	//初始验证规则
	//初始通用验证规则
	$.addRule({
		fn: function(val, validedRule, data) { //val待验证的值,validedRule要验证的规则 {name: 'tel', required: true, type: 'phone',msg: '请输入正确的手机号'}
			var required = validedRule.required;
			if (!required) return true;
			this.error = this.msg.replace("{1}", this.title);
			return !$.isBlank(val);

		},
		msg: "请输入{1}",
		name: "required"
	}).addRule({ //数字类型的值取值范围最小值
		fn: function(val, validedRule, data) {
			var min = validedRule.min;
			if (!min) return true;
			this.error = this.msg.replace("{1}", this.title).replace("{2}", min);
			return !$.isNull(min) && parseInt(val, 10) >= min;
		},
		msg: "{1}不能小于{2}",
		name: "min"
	}).addRule({ //数字类型的值取值范围最大值
		fn: function(val, validedRule, data) {
			var max = validedRule.max;
			if (!max) return true;
			this.error = this.msg.replace("{1}", this.title).replace("{2}", max);
			return !$.isNull(max) && parseInt(val, 10) <= max;
		},
		msg: "{1}不能大于{2}",
		name: "max"
	}).addRule({ //字符串长度取值范围最小长度
		fn: function(val, validedRule, data) {
			var min = validedRule.minLength;
			if (!min) return true;
			this.error = this.msg.replace("{1}", this.title).replace("{2}", min);
			return val.length >= min;
		},
		msg: "{1}长度不能小于{2}",
		name: "minLength"
	}).addRule({ //字符串长度取值范围最大长度
		fn: function(val, validedRule, data) {
			var max = validedRule.maxLength;
			if (!max) return true;
			this.error = this.msg.replace("{1}", this.title).replace("{2}", max);
			return val.length <= max;
		},
		msg: "{1}长度不能大于{2}",
		name: "maxLength"
	}).addRule({ //表单值等于另一个表单值
		fn: function(val, validedRule, data) {
			var eq = validedRule.eq;
			if (!eq) return true;
			this.error = this.msg.replace("{1}", this.title).replace("{2}", validedRule.eqTitle||eq);
			return val== data[eq];
		},
		msg: "{1}与{2}输入不一致",
		name: "eq"
	})
	//初始某个类型验证规则
	$.addRule("url", {
		fn: function(val, validedRule, data) {
			this.error = this.msg.replace("{1}", this.title);
			return $.isUrl(val);
		},
		msg: "字段{1}要求url格式",
		name: "url"
	}).addRule("email", {
		fn: function(val, validedRule, data) {
			this.error = this.msg.replace("{1}", this.title);
			return $.isEmail(val);
		},
		msg: "字段{1}要求邮件格式",
		name: "email"
	}).addRule("number", {
		fn: function(val, validedRule, data) {
			this.error = this.msg.replace("{1}", this.title);
			return $.isNumber(val);
		},
		msg: "{1}必须为数字",
		name: "number"
	}).addRule("int", {
		fn: function(val, validedRule, data) {
			this.error = this.msg.replace("{1}", this.title);
			return $.isInt(val);
		},
		msg: "{1}必须为整数",
		name: "int"
	}).addRule("tel", {
		fn: function(val, validedRule, data) {
			return $.isPhone(val);
		},
		msg: "请输入正确的手机号",
		name: "tel"
	}).addRule("password", {
		fn: function(val, validedRule, data) {
			return $.isPswd(val);
		},
		msg: "密码须是6～16位字符",
		name: "password"
	}).addRule("NumberLetter", {
		fn: function(val, validedRule, data) {
			this.error = this.msg.replace("{1}", this.title);
			return $.isNumberLetter(val);
		},
		msg: "{1}必须为数字和字符组成",
		name: "NumberLetter"
	}).addRule("regex", {
		fn: function(val, validedRule, data) { //// {name: 'xxx', type: 'regex', regex: /^1[0-9]{10,10}$/, msg: 'xxx'}
			this.error = this.msg.replace("{1}", this.title);
			return validedRule.regex && validedRule.regex.test(val);
		},
		msg: "{1}输入格式错误!",
		name: "regex"
	})
	return $;
})()
